<?php

class Form
{
    private function __construct(){}
    
    public static function _attributes_to_string($attributes, $formtag = FALSE)
    {
        if (is_string($attributes) AND strlen($attributes) > 0)
        {
            if ($formtag == TRUE AND strpos($attributes, 'method=') === FALSE)
            {
                $attributes .= ' method="post"';
            }

            if ($formtag == TRUE AND strpos($attributes, 'accept-charset=') === FALSE)
            {
                $attributes .= ' accept-charset="' . strtolower(config_item('charset')) . '"';
            }

            return ' ' . $attributes;
        }

        if (is_object($attributes) AND count($attributes) > 0)
        {
            $attributes = (array) $attributes;
        }

        if (is_array($attributes) AND count($attributes) > 0)
        {
            $atts = '';

            if (!isset($attributes['method']) AND $formtag === TRUE)
            {
                $atts .= ' method="post"';
            }

            if (!isset($attributes['accept-charset']) AND $formtag === TRUE)
            {
                $atts .= ' accept-charset="' . strtolower(config_item('charset')) . '"';
            }

            foreach ($attributes as $key => $val)
            {
                $atts .= ' ' . $key . '="' . $val . '"';
            }

            return $atts;
        }

    }

    public static function form_open($action = '', $attributes = '', $hidden = array())
    {

        if ($attributes == '')
        {
            $attributes = 'method="post"';
        }

        // If an action is not a full URL then turn it into one
        if ($action && strpos($action, '://') === FALSE)
        {
            $action = Config::get('app.url') . '/' . trim($action, '/');
        }

        // If no action is provided then set to the current url
        $action OR $action = Util::getUrl('page');

        $form = '<form action="' . $action . '"';

        $form .= self::_attributes_to_string($attributes, TRUE);

        $form .= '>';

        if (is_array($hidden) AND count($hidden) > 0)
        {
            $form .= sprintf("<div style=\"display:none\">%s</div>", self::form_hidden($hidden));
        }

        return $form;

    }

    public static function form_open_multipart($action = '', $attributes = array(), $hidden = array())
    {
        if (is_string($attributes))
        {
            $attributes .= ' enctype="multipart/form-data"';
        } else
        {
            $attributes['enctype'] = 'multipart/form-data';
        }

        return self::form_open($action, $attributes, $hidden);

    }

    public static function form_hidden($name, $value = '', $recursing = FALSE)
    {
        static $form;

        if ($recursing === FALSE)
        {
            $form = "\n";
        }

        if (is_array($name))
        {
            foreach ($name as $key => $val)
            {
                self::form_hidden($key, $val, TRUE);
            }
            return $form;
        }

        if (!is_array($value))
        {
            $form .= '<input type="hidden" name="' . $name . '" value="' . self::form_prep($value, $name) . '" />' . "\n";
        } else
        {
            foreach ($value as $k => $v)
            {
                $k = (is_int($k)) ? '' : $k;
                self::form_hidden($name . '[' . $k . ']', $v, TRUE);
            }
        }

        return $form;

    }

    public static function form_input($data = '', $value = '', $extra = '')
    {
        $defaults = array('type' => 'text', 'name' => ((!is_array($data)) ? $data : ''), 'value' => $value);

        return "<input " . self::_parse_form_attributes($data, $defaults) . $extra . " />";

    }

    public static function form_password($data = '', $value = '', $extra = '')
    {
        if (!is_array($data))
        {
            $data = array('name' => $data);
        }

        $data['type'] = 'password';
        return self::form_input($data, $value, $extra);

    }

    public static function form_textarea($data = '', $value = '', $extra = '')
    {
        $defaults = array('name' => ((!is_array($data)) ? $data : ''), 'cols' => '40', 'rows' => '10');

        if (!is_array($data) OR !isset($data['value']))
        {
            $val = $value;
        } else
        {
            $val = $data['value'];
            unset($data['value']); // textareas don't use the value attribute
        }

        $name = (is_array($data)) ? $data['name'] : $data;
        return "<textarea " . self::_parse_form_attributes($data, $defaults) . $extra . ">" . form_prep($val, $name) . "</textarea>";

    }

    public static function form_multiselect($name = '', $options = array(), $selected = array(), $extra = '')
    {
        if (!strpos($extra, 'multiple'))
        {
            $extra .= ' multiple="multiple"';
        }

        return self::form_dropdown($name, $options, $selected, $extra);

    }

    public static function form_dropdown($name = '', $options = array(), $selected = array(), $extra = '')
    {
        if (!is_array($selected))
        {
            $selected = array($selected);
        }

        // If no selected state was submitted we will attempt to set it automatically
        if (count($selected) === 0)
        {
            // If the form name appears in the $_POST array we have a winner!
            if (isset($_POST[$name]))
            {
                $selected = array($_POST[$name]);
            }
        }

        if ($extra != '')
            $extra = ' ' . $extra;

        $multiple = (count($selected) > 1 && strpos($extra, 'multiple') === FALSE) ? ' multiple="multiple"' : '';

        $form = '<select name="' . $name . '"' . $extra . $multiple . ">\n";

        foreach ($options as $key => $val)
        {
            $key = (string) $key;

            if (is_array($val) && !empty($val))
            {
                $form .= '<optgroup label="' . $key . '">' . "\n";

                foreach ($val as $optgroup_key => $optgroup_val)
                {
                    $sel = (in_array($optgroup_key, $selected)) ? ' selected="selected"' : '';

                    $form .= '<option value="' . $optgroup_key . '"' . $sel . '>' . (string) $optgroup_val . "</option>\n";
                }

                $form .= '</optgroup>' . "\n";
            } else
            {
                $sel = (in_array($key, $selected)) ? ' selected="selected"' : '';

                $form .= '<option value="' . $key . '"' . $sel . '>' . (string) $val . "</option>\n";
            }
        }

        $form .= '</select>';

        return $form;

    }

    public static function form_checkbox($data = '', $value = '', $checked = FALSE, $extra = '')
    {
        $defaults = array('type' => 'checkbox', 'name' => ((!is_array($data)) ? $data : ''), 'value' => $value);

        if (is_array($data) AND array_key_exists('checked', $data))
        {
            $checked = $data['checked'];

            if ($checked == FALSE)
            {
                unset($data['checked']);
            } else
            {
                $data['checked'] = 'checked';
            }
        }

        if ($checked == TRUE)
        {
            $defaults['checked'] = 'checked';
        } else
        {
            unset($defaults['checked']);
        }

        return "<input " . self::_parse_form_attributes($data, $defaults) . $extra . " />";

    }

    public static function form_radio($data = '', $value = '', $checked = FALSE, $extra = '')
    {
        if (!is_array($data))
        {
            $data = array('name' => $data);
        }

        $data['type'] = 'radio';
        return self::form_checkbox($data, $value, $checked, $extra);

    }

    public static function form_reset($data = '', $value = '', $extra = '')
    {
        $defaults = array('type' => 'reset', 'name' => ((!is_array($data)) ? $data : ''), 'value' => $value);

        return "<input " . self::_parse_form_attributes($data, $defaults) . $extra . " />";

    }

    public static function form_label($label_text = '', $id = '', $attributes = array())
    {

        $label = '<label';

        if ($id != '')
        {
            $label .= " for=\"$id\"";
        }

        if (is_array($attributes) AND count($attributes) > 0)
        {
            foreach ($attributes as $key => $val)
            {
                $label .= ' ' . $key . '="' . $val . '"';
            }
        }

        $label .= ">$label_text</label>";

        return $label;

    }

    public static function form_fieldset($legend_text = '', $attributes = array())
    {
        $fieldset = "<fieldset";

        $fieldset .= self::_attributes_to_string($attributes, FALSE);

        $fieldset .= ">\n";

        if ($legend_text != '')
        {
            $fieldset .= "<legend>$legend_text</legend>\n";
        }

        return $fieldset;

    }

    public static function form_fieldset_close($extra = '')
    {
        return "</fieldset>" . $extra;

    }

    public static function form_close($extra = '')
    {
        return "</form>" . $extra;

    }

    public static function form_prep($str = '', $field_name = '')
    {
        static $prepped_fields = array();

        // if the field name is an array we do this recursively
        if (is_array($str))
        {
            foreach ($str as $key => $val)
            {
                $str[$key] = self::form_prep($val);
            }

            return $str;
        }

        if ($str === '')
        {
            return '';
        }

        // we've already prepped a field with this name
        // @todo need to figure out a way to namespace this so
        // that we know the *exact* field and not just one_parse_form_attributes with
        // the same name
        if (isset($prepped_fields[$field_name]))
        {
            return $str;
        }

        $str = htmlspecialchars($str);

        // In case htmlspecialchars misses these.
        $str = str_replace(array("'", '"'), array("&#39;", "&quot;"), $str);

        if ($field_name != '')
        {
            $prepped_fields[$field_name] = $field_name;
        }

        return $str;

    }

    public static function _parse_form_attributes($attributes, $default)
    {
        if (is_array($attributes))
        {
            foreach ($default as $key => $val)
            {
                if (isset($attributes[$key]))
                {
                    $default[$key] = $attributes[$key];
                    unset($attributes[$key]);
                }
            }

            if (count($attributes) > 0)
            {
                $default = array_merge($default, $attributes);
            }
        }

        $att = '';

        foreach ($default as $key => $val)
        {
            if ($key == 'value')
            {
                $val = self::form_prep($val, $default['name']);
            }

            $att .= $key . '="' . $val . '" ';
        }

        return $att;

    }

}

